﻿// Decompiled with JetBrains decompiler
// Type: TaleWorlds.MountAndBlade.View.Scripts.CharacterSpawner
// Assembly: TaleWorlds.MountAndBlade.View, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
// MVID: 61152EB8-513B-4D4A-8AC0-0D1465C6CF6C
// Assembly location: D:\steam\steamapps\common\Mount & Blade II Bannerlord\Modules\Native\bin\Win64_Shipping_Client\TaleWorlds.MountAndBlade.View.dll

using TaleWorlds.Core;
using TaleWorlds.DotNet;
using TaleWorlds.Engine;
using TaleWorlds.Library;

#nullable disable
namespace TaleWorlds.MountAndBlade.View.Scripts
{
  public class CharacterSpawner : ScriptComponentBehavior
  {
    public bool Enabled;
    public string PoseAction = "act_walk_idle_unarmed";
    public string LordName = "main_hero_for_perf";
    public string ActionSetSuffix = "_facegen";
    public string PoseActionForHorse = "horse_stand_3";
    public string BodyPropertiesString = "<BodyProperties version=\"4\" age=\"23.16\" weight=\"0.3333\" build=\"0\" key=\"00000C07000000010011111211151111000701000010000000111011000101000000500202111110000000000000000000000000000000000000000000A00000\" />";
    public bool IsWeaponWielded;
    public bool HasMount;
    public bool WieldOffHand = true;
    public float AnimationProgress;
    public float HorseAnimationProgress;
    private MBGameManager _editorGameManager;
    private bool isFinished;
    private bool CreateFaceImmediately = true;
    private AgentVisuals _agentVisuals;
    private GameEntity _agentEntity;
    private GameEntity _horseEntity;
    public bool Active;
    private MatrixFrame _spawnFrame;

    public uint ClothColor1 { get; private set; }

    public uint ClothColor2 { get; private set; }

    ~CharacterSpawner()
    {
    }

    protected override void OnInit()
    {
      base.OnInit();
      this.ClothColor1 = uint.MaxValue;
      this.ClothColor2 = uint.MaxValue;
    }

    protected void Init() => this.Active = false;

    protected override void OnEditorInit()
    {
      base.OnEditorInit();
      if (Game.Current != null)
        return;
      this._editorGameManager = (MBGameManager) new EditorGameManager();
      this.isFinished = !this._editorGameManager.DoLoadingForGameManager();
    }

    protected override void OnEditorTick(float dt)
    {
      if (!this.Enabled)
        return;
      if (!this.isFinished && this._editorGameManager != null)
        this.isFinished = !this._editorGameManager.DoLoadingForGameManager();
      if (Game.Current == null || this._agentVisuals != null)
        return;
      this.SpawnCharacter();
      this.GameEntity.SetVisibilityExcludeParents(false);
      if ((NativeObject) this._agentEntity != (NativeObject) null)
        this._agentEntity.SetVisibilityExcludeParents(false);
      if (!((NativeObject) this._horseEntity != (NativeObject) null))
        return;
      this._horseEntity.SetVisibilityExcludeParents(false);
    }

    protected override void OnRemoved(int removeReason)
    {
      base.OnRemoved(removeReason);
      if (this._agentVisuals == null)
        return;
      this._agentVisuals.Reset();
      this._agentVisuals.GetVisuals().ManualInvalidate();
      this._agentVisuals = (AgentVisuals) null;
    }

    public void SetCreateFaceImmediately(bool value) => this.CreateFaceImmediately = value;

    private void Disable()
    {
      if ((NativeObject) this._agentEntity != (NativeObject) null && (NativeObject) this._agentEntity.Parent == (NativeObject) this.GameEntity)
        this.GameEntity.RemoveChild(this._agentEntity, false, false, true, 34);
      if (this._agentVisuals != null)
      {
        this._agentVisuals.Reset();
        this._agentVisuals.GetVisuals().ManualInvalidate();
        this._agentVisuals = (AgentVisuals) null;
      }
      if ((NativeObject) this._horseEntity != (NativeObject) null && (NativeObject) this._horseEntity.Parent == (NativeObject) this.GameEntity)
        this._horseEntity.Scene.RemoveEntity(this._horseEntity, 96);
      this.Active = false;
    }

    protected override void OnEditorVariableChanged(string variableName)
    {
      base.OnEditorVariableChanged(variableName);
      if (variableName == "Enabled")
      {
        if (this.Enabled)
          this.Init();
        else
          this.Disable();
      }
      if (!this.Enabled)
        return;
      switch (variableName)
      {
        case "LordName":
        case "ActionSetSuffix":
          if (this._agentVisuals == null)
            break;
          BasicCharacterObject character1 = Game.Current.ObjectManager.GetObject<BasicCharacterObject>(this.LordName);
          if (character1 == null)
            break;
          this.InitWithCharacter(CharacterCode.CreateFrom(character1), true);
          break;
        case "PoseActionForHorse":
          BasicCharacterObject character2 = Game.Current.ObjectManager.GetObject<BasicCharacterObject>(this.LordName);
          if (character2 == null)
            break;
          this.InitWithCharacter(CharacterCode.CreateFrom(character2), true);
          break;
        case "PoseAction":
          if (this._agentVisuals == null)
            break;
          BasicCharacterObject character3 = Game.Current.ObjectManager.GetObject<BasicCharacterObject>(this.LordName);
          if (character3 == null)
            break;
          this.InitWithCharacter(CharacterCode.CreateFrom(character3), true);
          break;
        case "IsWeaponWielded":
          this.WieldWeapon(CharacterCode.CreateFrom(Game.Current.ObjectManager.GetObject<BasicCharacterObject>(this.LordName)));
          break;
        case "AnimationProgress":
          Skeleton skeleton = this._agentVisuals.GetVisuals().GetSkeleton();
          skeleton.Freeze(false);
          skeleton.TickAnimationsAndForceUpdate(1f / 1000f, this._agentVisuals.GetVisuals().GetGlobalFrame(), false);
          skeleton.SetAnimationParameterAtChannel(0, MBMath.ClampFloat(this.AnimationProgress, 0.0f, 1f));
          skeleton.SetUptoDate(false);
          skeleton.Freeze(true);
          break;
        case "HorseAnimationProgress":
          if (!((NativeObject) this._horseEntity != (NativeObject) null))
            break;
          this._horseEntity.Skeleton.Freeze(false);
          this._horseEntity.Skeleton.TickAnimationsAndForceUpdate(1f / 1000f, this._horseEntity.GetGlobalFrame(), false);
          this._horseEntity.Skeleton.SetAnimationParameterAtChannel(0, MBMath.ClampFloat(this.HorseAnimationProgress, 0.0f, 1f));
          this._horseEntity.Skeleton.SetUptoDate(false);
          this._horseEntity.Skeleton.Freeze(true);
          break;
        case "HasMount":
          if (this.HasMount)
          {
            this.SpawnMount(CharacterCode.CreateFrom(Game.Current.ObjectManager.GetObject<BasicCharacterObject>(this.LordName)));
            break;
          }
          if (!((NativeObject) this._horseEntity != (NativeObject) null))
            break;
          this._horseEntity.Scene.RemoveEntity(this._horseEntity, 97);
          break;
        case "Active":
          this.GameEntity.SetVisibilityExcludeParents(this.Active);
          if ((NativeObject) this._agentEntity != (NativeObject) null)
            this._agentEntity.SetVisibilityExcludeParents(this.Active);
          if (!((NativeObject) this._horseEntity != (NativeObject) null))
            break;
          this._horseEntity.SetVisibilityExcludeParents(this.Active);
          break;
        case "FaceKeyString":
          BasicCharacterObject character4 = Game.Current.ObjectManager.GetObject<BasicCharacterObject>(this.LordName);
          if (character4 == null)
            break;
          this.InitWithCharacter(CharacterCode.CreateFrom(character4), true);
          break;
        case "WieldOffHand":
          BasicCharacterObject character5 = Game.Current.ObjectManager.GetObject<BasicCharacterObject>(this.LordName);
          if (character5 == null)
            break;
          this.InitWithCharacter(CharacterCode.CreateFrom(character5), true);
          break;
      }
    }

    public void SetClothColors(uint color1, uint color2)
    {
      this.ClothColor1 = color1;
      this.ClothColor2 = color2;
    }

    public void SpawnCharacter()
    {
      BasicCharacterObject character = Game.Current.ObjectManager.GetObject<BasicCharacterObject>(this.LordName);
      if (character == null)
        return;
      this.InitWithCharacter(CharacterCode.CreateFrom(character), true);
    }

    public void InitWithCharacter(CharacterCode characterCode, bool useBodyProperties = false)
    {
      this.GameEntity.BreakPrefab();
      if ((NativeObject) this._agentEntity != (NativeObject) null && (NativeObject) this._agentEntity.Parent == (NativeObject) this.GameEntity)
        this.GameEntity.RemoveChild(this._agentEntity, false, false, true, 35);
      this._agentVisuals?.Reset();
      this._agentVisuals?.GetVisuals()?.ManualInvalidate();
      if ((NativeObject) this._horseEntity != (NativeObject) null && (NativeObject) this._horseEntity.Parent == (NativeObject) this.GameEntity)
        this._horseEntity.Scene.RemoveEntity(this._horseEntity, 98);
      this._agentEntity = GameEntity.CreateEmpty(this.GameEntity.Scene, false);
      this._agentEntity.Name = "TableauCharacterAgentVisualsEntity";
      this._spawnFrame = this._agentEntity.GetFrame();
      BodyProperties bodyProperties = characterCode.BodyProperties;
      if (useBodyProperties)
        BodyProperties.FromString(this.BodyPropertiesString, out bodyProperties);
      if (characterCode.Color1 != uint.MaxValue)
        this.ClothColor1 = characterCode.Color1;
      if (characterCode.Color2 != uint.MaxValue)
        this.ClothColor2 = characterCode.Color2;
      Monster baseMonsterFromRace = TaleWorlds.Core.FaceGen.GetBaseMonsterFromRace(characterCode.Race);
      this._agentVisuals = AgentVisuals.Create(new AgentVisualsData().Equipment(characterCode.CalculateEquipment()).BodyProperties(bodyProperties).Race(characterCode.Race).Frame(this._spawnFrame).Scale(1f).SkeletonType(characterCode.IsFemale ? SkeletonType.Female : SkeletonType.Male).Entity(this._agentEntity).ActionSet(MBGlobals.GetActionSetWithSuffix(baseMonsterFromRace, characterCode.IsFemale, this.ActionSetSuffix)).ActionCode(ActionIndexCache.Create("act_inventory_idle_start")).Scene(this.GameEntity.Scene).Monster(baseMonsterFromRace).PrepareImmediately(this.CreateFaceImmediately).Banner(characterCode.Banner).ClothColor1(this.ClothColor1).ClothColor2(this.ClothColor2).UseMorphAnims(true), "TableauCharacterAgentVisuals", false, false, false);
      this._agentVisuals.SetAction(ActionIndexCache.Create(this.PoseAction), MBMath.ClampFloat(this.AnimationProgress, 0.0f, 1f), true);
      this.GameEntity.AddChild(this._agentEntity);
      this.WieldWeapon(characterCode);
      MatrixFrame identity = MatrixFrame.Identity;
      this._agentVisuals.GetVisuals().SetFrame(ref identity);
      if (this.HasMount)
        this.SpawnMount(characterCode);
      this.GameEntity.SetVisibilityExcludeParents(true);
      this._agentEntity.SetVisibilityExcludeParents(true);
      if ((NativeObject) this._horseEntity != (NativeObject) null)
        this._horseEntity.SetVisibilityExcludeParents(true);
      Skeleton skeleton = this._agentVisuals.GetVisuals().GetSkeleton();
      skeleton.Freeze(false);
      skeleton.TickAnimationsAndForceUpdate(1f / 1000f, this._agentVisuals.GetVisuals().GetGlobalFrame(), false);
      skeleton.SetUptoDate(false);
      skeleton.Freeze(true);
      this._agentEntity.SetBoundingboxDirty();
      skeleton.Freeze(false);
      skeleton.TickAnimationsAndForceUpdate(1f / 1000f, this._agentVisuals.GetVisuals().GetGlobalFrame(), false);
      skeleton.SetAnimationParameterAtChannel(0, MBMath.ClampFloat(this.AnimationProgress, 0.0f, 1f));
      skeleton.SetUptoDate(false);
      skeleton.Freeze(true);
      skeleton.ManualInvalidate();
      if ((NativeObject) this._horseEntity != (NativeObject) null)
      {
        this._horseEntity.Skeleton.Freeze(false);
        this._horseEntity.Skeleton.TickAnimationsAndForceUpdate(1f / 1000f, this._horseEntity.GetGlobalFrame(), false);
        this._horseEntity.Skeleton.SetUptoDate(false);
        this._horseEntity.Skeleton.Freeze(true);
        this._horseEntity.SetBoundingboxDirty();
      }
      if ((NativeObject) this._horseEntity != (NativeObject) null)
      {
        this._horseEntity.Skeleton.Freeze(false);
        this._horseEntity.Skeleton.TickAnimationsAndForceUpdate(1f / 1000f, this._horseEntity.GetGlobalFrame(), false);
        this._horseEntity.Skeleton.SetAnimationParameterAtChannel(0, MBMath.ClampFloat(this.HorseAnimationProgress, 0.0f, 1f));
        this._horseEntity.Skeleton.SetUptoDate(false);
        this._horseEntity.Skeleton.Freeze(true);
      }
      this.GameEntity.SetBoundingboxDirty();
      if (this.GameEntity.Scene.IsEditorScene())
        return;
      if ((NativeObject) this._agentEntity != (NativeObject) null)
        this._agentEntity.ManualInvalidate();
      if (!((NativeObject) this._horseEntity != (NativeObject) null))
        return;
      this._horseEntity.ManualInvalidate();
    }

    private void WieldWeapon(CharacterCode characterCode)
    {
      if (!this.IsWeaponWielded)
        return;
      WeaponFlags p2 = (WeaponFlags) 0;
      switch (characterCode.FormationClass)
      {
        case FormationClass.Infantry:
        case FormationClass.Cavalry:
        case FormationClass.NumberOfDefaultFormations:
        case FormationClass.HeavyInfantry:
        case FormationClass.LightCavalry:
        case FormationClass.NumberOfRegularFormations:
        case FormationClass.Bodyguard:
          p2 = WeaponFlags.MeleeWeapon;
          break;
        case FormationClass.Ranged:
        case FormationClass.HorseArcher:
          p2 = WeaponFlags.RangedWeapon;
          break;
      }
      int rightWieldedItemIndex = -1;
      int leftWieldedItemIndex = -1;
      Equipment equipment = characterCode.CalculateEquipment();
      for (int index = 0; index < 4; ++index)
      {
        if (equipment[index].Item?.PrimaryWeapon != null)
        {
          if (leftWieldedItemIndex == -1 && equipment[index].Item.ItemFlags.HasAnyFlag<ItemFlags>(ItemFlags.HeldInOffHand) && this.WieldOffHand)
            leftWieldedItemIndex = index;
          if (rightWieldedItemIndex == -1 && equipment[index].Item.PrimaryWeapon.WeaponFlags.HasAnyFlag<WeaponFlags>(p2))
            rightWieldedItemIndex = index;
        }
      }
      if (rightWieldedItemIndex == -1 && leftWieldedItemIndex == -1)
        return;
      AgentVisualsData agentVisualsData = this._agentVisuals.GetCopyAgentVisualsData();
      agentVisualsData.RightWieldedItemIndex(rightWieldedItemIndex).LeftWieldedItemIndex(leftWieldedItemIndex).ActionCode(ActionIndexCache.Create(this.PoseAction)).Frame(this._spawnFrame);
      this._agentVisuals.Refresh(false, agentVisualsData, false);
    }

    private void SpawnMount(CharacterCode characterCode)
    {
      Equipment equipment = characterCode.CalculateEquipment();
      ItemObject itemObject = equipment[EquipmentIndex.ArmorItemEndSlot].Item;
      if (itemObject == null)
      {
        this.HasMount = false;
      }
      else
      {
        this._horseEntity = GameEntity.CreateEmpty(this.GameEntity.Scene, false);
        this._horseEntity.Name = "MountEntity";
        Monster monster = itemObject.HorseComponent.Monster;
        MBActionSet actionSet = MBActionSet.GetActionSet(monster.ActionSetCode);
        this._horseEntity.CreateAgentSkeleton(actionSet.GetSkeletonName(), false, actionSet, monster.MonsterUsage, monster);
        this._horseEntity.CopyComponentsToSkeleton();
        this._horseEntity.Skeleton.SetAgentActionChannel(0, ActionIndexCache.Create(this.PoseActionForHorse), MBMath.ClampFloat(this.HorseAnimationProgress, 0.0f, 1f));
        this.GameEntity.AddChild(this._horseEntity);
        MountVisualCreator.AddMountMeshToEntity(this._horseEntity, equipment[10].Item, equipment[11].Item, MountCreationKey.GetRandomMountKeyString(equipment[10].Item, MBRandom.RandomInt()));
        this._horseEntity.SetVisibilityExcludeParents(true);
        this._horseEntity.Skeleton.TickAnimations(0.01f, this._agentVisuals.GetVisuals().GetGlobalFrame(), true);
      }
    }
  }
}
